package com.nord.WebTools;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.UnknownHostException;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.util.Log;
import android.widget.Toast;

import com.nord.EventList.EventList;
import com.nord.Login.Login;
import com.nord.NewsList.NewsList;
import com.nord.Services.SQLiteAdapter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
public class HtmlBrowser {
	/*
	 * Data invariant: httpBrowser is the main object that interacts with
	 * www.nord.is - Please note this object stores cookies. timeCalculus is a
	 * HashMap that contains enumeration information to match months found on
	 * the website - This is used to calculate time when an event is about to
	 * take place
	 */
	public static HttpClient httpBrowser;
	public static HashMap<String, Integer> timeCalculus;
	public static boolean onList;

	/*
	 * Usage: HtmlBrowser.initializeHashMap(); Post : HashMap is ready for usage
	 */
	public static void initializeHashMap() {
		timeCalculus = new HashMap<String, Integer>();

		timeCalculus.put("Jan", 0);
		timeCalculus.put("Feb", 1);

		timeCalculus.put("Mar", 2);
		timeCalculus.put("Mars", 2);

		timeCalculus.put("Apríl", 3);
		timeCalculus.put("Apr", 3);

		timeCalculus.put("Maí", 4);
		timeCalculus.put("May", 4);

		timeCalculus.put("Júní", 5);
		timeCalculus.put("Jun", 5);

		timeCalculus.put("Jul", 6);
		timeCalculus.put("Júlí", 6);

		timeCalculus.put("Aug", 7);
		timeCalculus.put("Ág", 7);

		timeCalculus.put("Sept", 8);
		timeCalculus.put("Sep", 8);

		timeCalculus.put("Oct", 9);
		timeCalculus.put("Okt", 9);

		timeCalculus.put("Nóv", 10);
		timeCalculus.put("Nov", 10);

		timeCalculus.put("Dec", 11);
		timeCalculus.put("Des", 11);

	}

	/*
	 * Usage: HtmlBrowser.initBrowser(); Eftir : A new instance of HttpClient is
	 * ready for use.
	 */
	public static void initBrowser() {
		httpBrowser = getTrustedHttpClient();
		httpBrowser.getParams().setParameter(CoreProtocolPNames.USER_AGENT,
				"Nord-App");
	}

	/*
	 * Usage: HttpClient c = HtmlBrowser.getTrustedHttpClient(); Post : A new
	 * instance of HttpClient is returned - Please note this instance permits
	 * the license on https://www.nord.is/
	 */
	public static HttpClient getTrustedHttpClient() {
		try {
			KeyStore trustStore = KeyStore.getInstance(KeyStore
					.getDefaultType());
			trustStore.load(null, null);

			SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
			sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

			HttpParams params = new BasicHttpParams();
			HttpConnectionParams.setConnectionTimeout(params, 8000);
			HttpConnectionParams.setSoTimeout(params, 8000);

			HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
			HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
			HttpProtocolParams.setHttpElementCharset(params, HTTP.UTF_8);

			SchemeRegistry registry = new SchemeRegistry();
			registry.register(new Scheme("http", PlainSocketFactory
					.getSocketFactory(), 80));
			registry.register(new Scheme("https", sf, 443));

			ClientConnectionManager ccm = new ThreadSafeClientConnManager(
					params, registry);
			return new DefaultHttpClient(ccm, params);
		} catch (Exception e) {
			return new DefaultHttpClient();
		}
	}

	/*
	 * Usage: String s = HtmlBrowser.inputStreamToString(InputStream); Pre :
	 * There exists an instance of InputStream Post : HTML of the webpage is
	 * returned as a single string object
	 */
	public static StringBuilder inputStreamToString(InputStream is) {
		String line = "";
		StringBuilder total = new StringBuilder();
		// Wrap a BufferedReader around the InputStream
		BufferedReader rd = new BufferedReader(new InputStreamReader(is));
		// Read response until the end
		try {
			while ((line = rd.readLine()) != null) {
				total.append(line);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		// Return full string
		return total;
	}

	/*
	 * Usage: BasicClientCookie[] cookies = loadCookies(); Post : Cookies have
	 * been extracted from the database and returned
	 */
	public static BasicClientCookie[] loadCookies(Context context) {
		SQLiteAdapter mySQLiteAdapter = new SQLiteAdapter(context);
		mySQLiteAdapter.open("R");
		String[]columns = {
				"version",
				"name",
				"value",
				"domain",
				"path",
				"expdate",
				"username"
		};
		Cursor cursor = mySQLiteAdapter.queryTable("cookies",columns);
		BasicClientCookie[] cookies = new BasicClientCookie[2];
		if (cursor.moveToFirst()) {
			for (int n = 0; n < cursor.getCount(); n++) {
				/* We have loaded n Cookies from the database */
				cookies[n] = new BasicClientCookie(cursor.getString(cursor
						.getColumnIndex("name")), null);
				for (int k = 0; k < cursor.getColumnCount(); k++) {
					/* We have set the correct attribute k for Cookie n */
					if (cursor.getColumnName(k).contains("version")) {
						cookies[n].setVersion(Integer.parseInt(cursor
								.getString(k)));
					}

					if (cursor.getColumnName(k).contains("value")) {
						cookies[n].setValue(cursor.getString(k));
					}

					if (cursor.getColumnName(k).contains("domain")) {
						cookies[n].setDomain(cursor.getString(k));
					}

					if (cursor.getColumnName(k).contains("path")) {
						cookies[n].setPath(cursor.getString(k));
					}

					if (cursor.getColumnName(k).contains("expdate")) {
						cookies[n].setExpiryDate(null);
					}
				}
				cursor.moveToNext();
			}
		}
		cursor.close();
		mySQLiteAdapter.close();
		return cookies;
	}

	/*
	 * Usage: String html = HtmlBrowser.getExecutor(String); Pre : There exists
	 * an instance of HttpClient
	 * 
	 * Post : HTML is returned after a GET request on the server or an error
	 * message
	 */
	public static String[] getExecutor(String request) {
		String[] responseInfo = new String[3];
		try {
			long startTime = System.currentTimeMillis();
			HttpResponse httpRequest = httpBrowser
					.execute(new HttpGet(request));
			long elapsedTime = System.currentTimeMillis() - startTime;
			responseInfo[0] = inputStreamToString(
					httpRequest.getEntity().getContent()).toString();
			responseInfo[1] = httpRequest.getLastHeader("Date").getValue();
			responseInfo[2] = String.valueOf(elapsedTime);
			return responseInfo;

		} catch (IOException e) {
			// TODO Auto-generated catch block
			responseInfo[0] = e.toString();
			responseInfo[1] = "";
			return responseInfo;
		}
	}

	/*
	 * Usage: String html = HtmlBrowser.postExecutor(String,
	 * List<NameValuePair>); Pre : There exists an instance of HttpClient Post :
	 * HTML is returned after a POST request on the server or an error message
	 */
	public static String[] postExecutor(String request, List<NameValuePair> info) {
		String[] responseInfo = new String[2];
		try {
			HttpPost httpPost = new HttpPost(request);
			httpPost.setHeader("Referer", request);
			httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
			httpPost.setEntity(new UrlEncodedFormEntity(info, HTTP.UTF_8));
					
			HttpResponse httpRequest = httpBrowser.execute(httpPost);
			responseInfo[0] = inputStreamToString(httpRequest.getEntity().getContent()).toString();
			if(httpRequest.getLastHeader("Set-Cookie") != null){
				responseInfo[1] = "OUT";
			}
			else {
				responseInfo[1] = "IN";
			}
			return responseInfo;
			

		} catch (IOException e) {
			responseInfo[0] = e.toString();
			responseInfo[1] = "Exception";
			return responseInfo;
		}

	}
	/*
	 * Notkun: s = timeCalculator(String[], String) 
	 * Fyrir : Til er dagsetning af tagi 
	 * String[] 0: Nafn a degi (Mon) 
	 * 		1: Tala a degi i manudi (01) 
	 * 		2: Nafn a manudi (Jan) 
	 * 		3: Tala a ari (1970) 
	 * 		4: Tala a tima (00:00:00) 
	 * Hinn strengurinn er scrape-adur fra sidunni, Formid er: 'bil'00:00 1. Jan ..
	 * Thad tharf ad formatta hann pinu.
	 * Eftir : Millisekundur i eventinn.
	 */
	public static long timeCalculator(String serverTime, String eventData) {
		serverTime = serverTime.replace(",", "");

		String[] serverSplit = serverTime.split(" ");
		String[] serverTimeSplit = serverSplit[4].split(":");
		String[] eventSplit = eventData.split("T");
		String[] eventDateSplit = eventSplit[0].split("-");
		String[] eventTimeSplit = eventSplit[1].split(":");
		
		Calendar server = Calendar.getInstance();
		server.clear();
		server.set(
				Integer.parseInt(serverSplit[3]),
				HtmlBrowser.timeCalculus.get(serverSplit[2]),
				Integer.parseInt(serverSplit[1]),
				Integer.parseInt(serverTimeSplit[0]),
				Integer.parseInt(serverTimeSplit[1]),
				Integer.parseInt(serverTimeSplit[2])
				);

		Calendar event = Calendar.getInstance();
		event.clear();
		event.set(
				Integer.parseInt(eventDateSplit[0]),
				Integer.parseInt(eventDateSplit[1]) - 1,
				Integer.parseInt(eventDateSplit[2]),
				Integer.parseInt(eventTimeSplit[0]),
				Integer.parseInt(eventTimeSplit[1]),
				Integer.parseInt(eventTimeSplit[2])
				);
		
		return event.getTimeInMillis() - server.getTimeInMillis();
	}

	/*
	 * Usage: HtmlBrowser.expiredCookieHandler(Context); Post : An invalid
	 * cookie exists. User is prompted to refresh login
	 */
	public static void expiredCookieHandler(Context context) {
		Toast toast = Toast.makeText(context, "Innskráning rann út",
				Toast.LENGTH_LONG);
		toast.show();
		Intent login = new Intent(context, Login.class);
		context.startActivity(login);
	}


	/*
	 * Usage: List<HashMap <String, String>> =
	 * HtmlBrowser.internetLessEventHandler(Context); Post : Limited information
	 * regarding event has been returned
	 */
	/*public static List<HashMap<String, String>> internetLessEventHandler(
			Context context) {
		List<HashMap<String, String>> returnInfo = new ArrayList<HashMap<String, String>>();
		SQLiteAdapter sqLiteAdapter = new SQLiteAdapter(context);
		sqLiteAdapter.open("R");
		Cursor cursor = sqLiteAdapter.queryEvents();
		if (cursor.getCount() != 0) {
			if (cursor.moveToFirst()) {
				for (int i = 0; i < cursor.getCount(); i++) {
					HashMap<String, String> map = new HashMap<String, String>();
					map.put("eventname", cursor.getString(cursor
							.getColumnIndex("eventname")));
					map.put("eventdate",
							"Atburður hefst:"
									+ cursor.getString(cursor
											.getColumnIndex("eventdate")));
					map.put("url",
							cursor.getString(cursor.getColumnIndex("url")));
					map.put("countdown", "Ekkert Netsamband");
					returnInfo.add(map);
					cursor.moveToNext();
				}
			}
			cursor.close();
			sqLiteAdapter.close();
			return returnInfo;
		}
		sqLiteAdapter.close();
		return null;
	}*/

	public static Boolean cookieValidation(String serverTime, Context context){
		SQLiteAdapter sql = new SQLiteAdapter(context);
		sql.open("R");
		String[] columns = {
				"version",
				"name",
				"value",
				"domain",
				"path",
				"expdate",
				"username"};
		Cursor cursor = sql.queryTable("cookies", columns);
		if(cursor.getCount() != 0){
			cursor.moveToLast();
			serverTime = serverTime.replace(",", "");
			String serverArray[] = serverTime.split(" ");
			String cookieArray[] = cursor.getString(cursor.getColumnIndex("expdate")).split(" ");
			cursor.close();
			sql.close();	
			if(Integer.parseInt(serverArray[3]) == Integer.parseInt(cookieArray[0])){
				if(HtmlBrowser.timeCalculus.get(serverArray[2]) == Integer.parseInt(cookieArray[1])){
					if(Integer.parseInt(cookieArray[2]) - Integer.parseInt(serverArray[1]) > 1){
						return true;
					}
					return false;
				}
				else if(HtmlBrowser.timeCalculus.get(serverArray[2]) < Integer.parseInt(cookieArray[1])){
					return true;
				}
				return false;
			} 
			else if(Integer.parseInt(serverArray[3]) < Integer.parseInt(cookieArray[0])){
				return true;
			}
		}
		cursor.close();
		sql.close();		
		return false;
	}
	
	/*
	 * Usage: List<HashMap<String,String>> map =
	 * HtmlBrowser.stringPhoneBookProcessor(String) Pre : A valid HTML has been
	 * received from the browser Post : A list of hashmaps that include user
	 * information has been returned The maps include: name, email and phone
	 * number
	 */
	public static String findFullName(String username){
		String json[] = HtmlBrowser.getExecutor("http://www.nord.is/api/nord/users/?format=json&limit=0");
		try {
				JSONObject object = new JSONObject(json[0]);
				JSONArray data = object.getJSONArray("objects");
				for(int i = 0; i < data.length();i++){
					if(data.getJSONObject(i).get("username").toString().compareTo(username) == 0){
						return data.getJSONObject(i).get("full_name").toString();				
					}
				}		
			} catch (Exception e){}
		return "";
	}
	
	public static Cursor jsonPhoneBookProcessor(SQLiteAdapter sql, String jsonString) 
	{
		try {
			JSONObject object = new JSONObject(jsonString);
			JSONArray data = object.getJSONArray("objects");
			for(int i = 0; i < data.length();i++){				
				ContentValues contentValues = new ContentValues();
				contentValues.put("fullname", data.getJSONObject(i).get("full_name").toString());
				if(!data.getJSONObject(i).get("phone").toString().contains("null"))
					contentValues.put("phonenumber", data.getJSONObject(i).get("phone").toString());
				else
					contentValues.put("phonenumber", "Ekkert símanúmer skráð");
				contentValues.put("email", data.getJSONObject(i).get("username").toString() + "@hi.is");
				sql.insert("phonebook", contentValues);
			}
			Cursor cursor = sql.queryPhoneBook();			
			return cursor;
		} catch(JSONException e){
			return null;
		}
	}
	
	public static List<HashMap<String, String>> jsonNewsProcessor(String jsonString, Context context, String username) {
		List<HashMap<String, String>> info = new ArrayList<HashMap<String, String>>();
		SQLiteAdapter sql = new SQLiteAdapter(context);
		sql.open("W");
		sql.deleteAll("news");
		try {
			JSONObject object = new JSONObject(jsonString);
			JSONArray data = object.getJSONArray("objects");
			for(int i = 0; i < data.length();i++){
				HashMap<String, String> map = new HashMap<String, String>();
				map.put("title", data.getJSONObject(i).get("title").toString());
				map.put("body", data.getJSONObject(i).get("body").toString());
				map.put("date", data.getJSONObject(i).get("date").toString());
				map.put("id", data.getJSONObject(i).get("id").toString());
				map.put("translation", data.getJSONObject(i).get("translation").toString());
				map.put("likers", data.getJSONObject(i).get("likers_count").toString());
				map.put("lovers", data.getJSONObject(i).get("lovers_count").toString());
				map.put("comments", data.getJSONObject(i).get("comment_url").toString());
				map.put("author", data.getJSONObject(i).get("author").toString());			
				map.put("slug", data.getJSONObject(i).get("slug").toString());			
				
				ContentValues contentValues = new ContentValues();
				contentValues.put("title", data.getJSONObject(i).get("title").toString());
				contentValues.put("body", data.getJSONObject(i).get("body").toString());
				contentValues.put("date",data.getJSONObject(i).get("date").toString());
				contentValues.put("id", data.getJSONObject(i).get("id").toString());
				contentValues.put("translation", data.getJSONObject(i).get("translation").toString());
				contentValues.put("likers", data.getJSONObject(i).get("likers_count").toString());
				contentValues.put("lovers", data.getJSONObject(i).get("lovers_count").toString());
				contentValues.put("comments", data.getJSONObject(i).get("comment_url").toString());
				contentValues.put("author", data.getJSONObject(i).get("author").toString());
				contentValues.put("slug", data.getJSONObject(i).get("slug").toString());			
				
				for(int j = 0;j < data.getJSONObject(i).getJSONArray("likers").length();j++){
					if(data.getJSONObject(i).getJSONArray("likers").getJSONObject(j).get("full_name").toString()
							.compareTo(username) == 0){
						map.put("liked", "true");
						break;
					}
				}

				for(int j = 0;j < data.getJSONObject(i).getJSONArray("lovers").length();j++){
					if(data.getJSONObject(i).getJSONArray("lovers").getJSONObject(j).get("full_name").toString()
							.compareTo(username) == 0){
						map.put("loved", "true");
						break;
					}
				}
				sql.insert("news",contentValues);
				info.add(map);
			}		
			sql.close();			
			return info;
		} catch(JSONException e) {
			return null;
		}
	}
	
	public static ArrayList<ArrayList<String>> jsonNewsCommentProcessor(String body, String id,String jsonString){
		ArrayList<ArrayList<String>> comments = new ArrayList<ArrayList<String>>();
		try{
			JSONObject object = new JSONObject(jsonString);
			JSONArray data = object.getJSONArray("objects");
			for(int i = 0; i < data.length();i++){
				ArrayList<String> comment = new ArrayList<String>();
				comment.add(data.getJSONObject(i).get("comment").toString());
				comment.add(data.getJSONObject(i).get("user_name").toString());
				comment.add(prettyDate(data.getJSONObject(i).get("submit_date").toString()));
				comments.add(comment);
			}
			
		}  catch(JSONException e) {
			return comments;
		}
		return comments;
		
	}

	public static List<HashMap<String,String>> getUsersFromJSON(String jsonString, String eventName){
		List<HashMap<String,String>> users = new ArrayList<HashMap<String,String>>();
		try{
			JSONObject object = new JSONObject(jsonString);
			JSONArray data = object.getJSONArray("objects");
			for(int i = 0; i < data.length();i++){
				if(data.getJSONObject(i).get("title").toString().compareTo(eventName) == 0){
					int userCount = data.getJSONObject(i).getJSONArray("registrations").length()-1;
					for(int j = userCount; j >= 0 ;j--){
						HashMap <String,String> user = new HashMap<String,String>();
						user.put("position", String.valueOf((-1 * (j - userCount)) + 1));
						user.put("name", 
								data.getJSONObject(i).getJSONArray("registrations").getJSONObject(j).get("full_name").toString());
						if(data.getJSONObject(i).getJSONArray("registrations").getJSONObject(j).getBoolean("checkbox"))
							user.put("checkbox",data.getJSONObject(i).getString("checkbox").toString());
						users.add(user);
					}
					break;
				}
			}
		} catch(Exception e){}
		return users;
	}
	public static List<HashMap<String, String>> jsonEventProcessor(String jsonString, String serverTime,Context context){
		List<HashMap<String, String>> events = new ArrayList<HashMap<String, String>>();
		ContentValues contentValues;
		SQLiteAdapter sql = new SQLiteAdapter(context);
		sql.open("W");
		sql.deleteAll("events");
		try{
			JSONObject object = new JSONObject(jsonString);
			JSONArray data = object.getJSONArray("objects");
			for(int i = 0; i < data.length();i++){
				String date = data.getJSONObject(i).get("date").toString();
				if(HtmlBrowser.timeCalculator(serverTime,date) > 0){
					HashMap<String,String> event = new HashMap<String,String>();
					event.put("title", data.getJSONObject(i).get("title").toString());
					event.put("max", data.getJSONObject(i).get("max_attendees").toString());
					event.put("date", data.getJSONObject(i).get("date").toString());
					event.put("start", 
							String.valueOf(HtmlBrowser.timeCalculator(
									serverTime,data.getJSONObject(i).get("registration_startdate").toString())));
					event.put("end", 
							String.valueOf(HtmlBrowser.timeCalculator(
									serverTime,data.getJSONObject(i).get("registration_closedate").toString())));
					
					event.put("checkbox", data.getJSONObject(i).get("checkbox").toString());
					event.put("id", data.getJSONObject(i).get("id").toString());
					event.put("slug", data.getJSONObject(i).get("slug").toString());
					events.add(event);
									
					contentValues = new ContentValues();
					contentValues.put("eventname", data.getJSONObject(i).get("title").toString());
					contentValues.put("eventdate", data.getJSONObject(i).get("date").toString());
					contentValues.put("max", data.getJSONObject(i).get("max_attendees").toString());
					contentValues.put("checkbox", data.getJSONObject(i).get("checkbox").toString());
					sql.insert("events", contentValues);
				}
			}
		}  catch(JSONException e) {
			sql.close();
			return events;
		}
		sql.close();
		return events;
	}
	
	public static String prettyDate(String date)
	{
		String [] split = date.split("T");
		String time = split[1].substring(0,split[1].indexOf("."));
		split = split[0].split("-");
		return time + " " + split[2] + "/" + split[1] + "/" + split[0];
	}
}
